home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 July: Mac OS SDK / Dev.CD Jul 00 SDK2.toast / Development Kits / Hardware / Mac OS USB DDK / Mac OS USB DDK 1.4.1 / Examples / USBSampleStorageDriver / UnitTableDriver / UnitTableReadWriteSupport.c < prev    next >
Encoding:
Text File  |  2000-04-25  |  27.7 KB  |  782 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        UnitTableReadWriteSupport.c
  3.  
  4.     Contains:    Handles read and write requests.  Also handles all filesystem
  5.                 to device block conversions.
  6.  
  7.     Version:    1.0
  8.  
  9.     Copyright:    Â© 1999 by Apple Computer, Inc., all rights reserved.
  10.  
  11. */
  12.  
  13. // All system header includes
  14. #include <Devices.h>
  15. #include <DriverServices.h>
  16. #include <Errors.h>
  17.  
  18. // Unit Table Driver specific headers
  19. #include "UnitTableReadWriteSupport.h"
  20. #include "UnitTableDeviceAccess.h"
  21. #include "UnitTableDriveQSupport.h"
  22.  
  23. typedef struct IntReadWritePB
  24. {
  25.     UInt32                            userData;
  26.     ReadWriteCompletionProcPtr        userCompletion;
  27.     volatile OSStatus                status;
  28.     UInt32                             startBlock;
  29.     UInt32                             blockCount;
  30.     Boolean                            convertToSystemBlocks;
  31.     UInt32                            reqCount;
  32.     Ptr                                userBuffer;
  33.     UInt16                            retryCount;
  34.     UInt32                             blockSize;
  35.     Boolean                            doWrite;
  36.     UInt8                            currentExecutionState;
  37.     SGList                            theSGList;
  38.     SGElement                        sgElements[4];
  39.     UInt32                            leadDataStart;
  40.     UInt32                            leadDataEnd;
  41.     UInt32                            trailDataCount;
  42. } IntReadWritePB, *IntReadWritePBPtr;
  43.  
  44. static IntReadWritePB gReadWritePB;
  45.  
  46. enum
  47. {
  48.     kMaxSupportedBlocksize = 2048
  49. };
  50.  
  51. enum 
  52. {
  53.     kReadWriteRetryCount = 5
  54. };
  55.  
  56. static OSStatus ConvertSystemBlocksToDriveBlocks(    IntReadWritePBPtr     readWritePB );
  57.  
  58. static void     ReadScatterGatherCompletion(    UInt32                userData,
  59.                                                 OSStatus            status );
  60.  
  61. static void     WriteReadTrailingOnlyCompletion(     UInt32                 userData, 
  62.                                                 OSStatus            status );
  63.                                                 
  64. static void     WriteReadLeadingCompletion(     UInt32                 userData, 
  65.                                                 OSStatus            status );
  66.                                                 
  67. static void     WriteReadTrailingCompletion(     UInt32                 userData, 
  68.                                                 OSStatus            status );
  69.                                                 
  70. static void     ReadWriteCompletion(            UInt32                userData,
  71.                                                 OSStatus            status );
  72.  
  73. /* ---------------------Supporting Functions below this point -------------------------- */
  74. //------------------------------------------------------------------------------
  75. //    Function:        DoReadWriteCommand
  76. //    Description:    This is the entry point for all Read and Write
  77. //                    requests passed through DoDriverIO.
  78. //                    
  79. //    Input:            ioPB = Pointer to caller's I/O parameter block
  80. //
  81. //    Output:            A status code is returned (status is equal to 1
  82. //                    if command is pending completion).
  83. //-------------------------------------------------------------------------------
  84. OSStatus DoReadWriteCommand( UInt32 userData, IOParamPtr iopb, UInt16 driveNum, Boolean doWrite, ReadWriteCompletionProcPtr    callback )
  85. {
  86.     OSStatus        err;
  87.     UInt32            startingBlock, numBlocks;
  88.     UInt32            standardBlockSize = kFileSystemRequestBlockSize;
  89.     DriveQRecPtr    drive;
  90.  
  91.     // Save the parameters ino our internal parameter block
  92.     BlockZero( &gReadWritePB, sizeof( IntReadWritePB ));
  93.     gReadWritePB.userData            = userData;
  94.     gReadWritePB.userCompletion        = callback;
  95.     gReadWritePB.doWrite            = doWrite;
  96.  
  97.     // Find the associated volume and drive records required for the request.
  98.     drive = FindDriveQRecForDriveNum( driveNum );            // Get the volume record requested 
  99.     
  100.     if ( drive == nil )                                        // Abort if we can't find a valid drive
  101.     {
  102.         return( nsDrvErr );
  103.     }
  104.  
  105.     gReadWritePB.blockSize            = drive->blockSize;
  106.     
  107.     // Make sure that the request is converted from native blocks to system blocks if necessary.
  108.     gReadWritePB.convertToSystemBlocks    = true;
  109.     //................................................................................
  110.     // A usable drive and volume exists.  Continue processing the request…
  111.  
  112.     // Compute the starting block address for the request.  We accept either
  113.     // the new 'Large Volume (64 bit) Addressing' or the normal 32 bit address.
  114.     if (iopb->ioPosMode & kUseWidePositioning)        // If 'wide' address is used
  115.     {
  116.         XIOParam        *widePB;
  117.         
  118.         widePB = (XIOParam *) iopb;
  119.                 
  120.         startingBlock = (widePB->ioWPosOffset.hi & 0XFC00);        // Verify whether a valid 52 bit address
  121.         if (startingBlock != 0)
  122.             return(paramErr);            // address too large
  123.  
  124.         // The address is a 64 bit big-endian integer (only 52 bits are used for now).
  125.         // Divide by 512 to get a 32 bit block address.  This translates as follows:
  126.         //        byte address bits 00-31 = block address bits 00-22
  127.         //         byte address bits 32-51 = block address bits 23-31
  128.         startingBlock = (widePB->ioWPosOffset.hi << 23);    // block address bits 23-31
  129.         startingBlock |= (widePB->ioWPosOffset.lo >> 9);    // block address bits 00-23
  130.     } 
  131.     else
  132.     {
  133.         // traditional 32 bit address
  134.         startingBlock = (UInt32)((iopb->ioPosOffset)/(standardBlockSize));
  135.     }
  136.     
  137.     numBlocks = (iopb->ioReqCount)/(standardBlockSize);
  138.  
  139.     if (doWrite && drive->driveStatus.writeProt)
  140.     {
  141.         // check for write protect
  142.         err = wPrErr;
  143.     }
  144.     else if (iopb->ioReqCount & ((standardBlockSize) - 1))
  145.     {
  146.         // Verify if request is a multiple of the file system request blocksize
  147.         err = paramErr;
  148.     }
  149.     else if ( ( startingBlock + numBlocks ) > ((drive->curoffset) ? drive->partblks : drive->capacity))
  150.     {
  151.         // Verify if request is within range with respect to doing physical or logical I/O.
  152.         // Access is limited to partition range (logical I/O) if curoffset is non-zero.
  153.         err = paramErr;
  154.     }
  155.     else if ((iopb->ioPosMode & rdVerify) && !doWrite)
  156.     {
  157.         // If Read-Verify mode, this is not efficient with disks so we simply pretend we did it.
  158.         iopb->ioActCount = iopb->ioReqCount;
  159.         iopb->ioPosOffset += iopb->ioActCount;
  160.         err = noErr;
  161.     } 
  162.     else                                    // Do the read or write
  163.     {
  164.         startingBlock += drive->curoffset;    // add in the partition offset
  165.  
  166.         gReadWritePB.startBlock = startingBlock;
  167.         gReadWritePB.blockCount = numBlocks;
  168.         gReadWritePB.userBuffer = iopb->ioBuffer;
  169.         gReadWritePB.reqCount = iopb->ioReqCount;
  170.         err = ConvertSystemBlocksToDriveBlocks( &gReadWritePB );
  171.     }
  172.  
  173.     return err;
  174. }
  175.  
  176. OSStatus DoReadWritePhysicalBlocks ( UInt32                            userData,
  177.                                     UInt32                            startBlock,
  178.                                     UInt32                            blockCount,
  179.                                     UInt32                            blockSize,
  180.                                     Boolean                            convertToSystemBlocks,
  181.                                     Ptr                                buffer,
  182.                                     UInt32                            byteCount,
  183.                                     Boolean                            doWrite,
  184.                                     ReadWriteCompletionProcPtr        callBack)
  185. {
  186.     OSStatus err;
  187.     
  188.     // Save the parameters ino our internal parameter block
  189.     BlockZero( &gReadWritePB, sizeof( IntReadWritePB ));
  190.     gReadWritePB.userData            = userData;
  191.     gReadWritePB.userCompletion        = callBack;
  192.     gReadWritePB.blockSize            = blockSize;
  193.     gReadWritePB.doWrite            = doWrite;
  194.     gReadWritePB.startBlock         = startBlock;
  195.     gReadWritePB.blockCount         = blockCount;
  196.     gReadWritePB.userBuffer         = buffer;
  197.     gReadWritePB.reqCount             = byteCount;
  198.     gReadWritePB.convertToSystemBlocks    = convertToSystemBlocks;
  199.     
  200.     // Check to make sure that if we are not converting to system
  201.     // blocks, that the request is actually a multiple of the
  202.     // native block size of the device.
  203.     if (( convertToSystemBlocks == false ) && (( byteCount % blockSize ) != 0 ))
  204.     {
  205.         err = ioErr;
  206.     }
  207.     else
  208.     {
  209.         err = ConvertSystemBlocksToDriveBlocks( &gReadWritePB );
  210.     }
  211.  
  212.     return err;
  213. }
  214.  
  215. // Our buffers for deblocking the requests
  216. static UInt8 LeadingBlockBuffer[kMaxSupportedBlocksize];
  217. static UInt8 TrailingBlockBuffer[kMaxSupportedBlocksize];
  218.  
  219. OSStatus ConvertSystemBlocksToDriveBlocks( IntReadWritePBPtr readWritePB )
  220. {
  221.     OSStatus        err;
  222.     UInt32            startingDriveBlock, numDriveBlocks;
  223.     UInt32            standardBlockSize = kFileSystemRequestBlockSize;
  224.     
  225.     if (( readWritePB->blockSize == standardBlockSize ) || ( readWritePB->convertToSystemBlocks == false ))
  226.     {
  227.         // The drive's blocksize is the same as the system's or we are ask not to do th conversion, 
  228.         // we do not need to do anything else, but send this request.
  229.         err = ReadWriteSingleBuffer(    (UInt32) readWritePB,
  230.                                         readWritePB->startBlock,
  231.                                         readWritePB->blockCount,
  232.                                         readWritePB->userBuffer,
  233.                                         readWritePB->reqCount,
  234.                                         readWritePB->doWrite,
  235.                                         &ReadWriteCompletion );
  236.     }
  237.     else
  238.     {
  239.         // The drive's block size is greater than the system defaut block size.
  240.         // Each request needs to be examined to see if it can be completed as a single
  241.         // buffer command, a scatter-gather command or if it requires additional read
  242.         // commands to complete
  243.         UInt8    sysBlksPrDriveBlk;
  244.         
  245.         sysBlksPrDriveBlk = (readWritePB->blockSize)/standardBlockSize;
  246.         if (( ( readWritePB->startBlock % sysBlksPrDriveBlk) == 0 )
  247.             && ( (readWritePB->blockCount % sysBlksPrDriveBlk) == 0 ))
  248.         {
  249.             // The starting block is on a drive block boundary and
  250.             // the blockCount is a multiple of drive blocks
  251.             // modify the start block and block count and send as 
  252.             // a single buffer request.
  253.             startingDriveBlock     = (readWritePB->startBlock)/sysBlksPrDriveBlk;
  254.             numDriveBlocks         = (readWritePB->blockCount)/sysBlksPrDriveBlk;
  255.             err = ReadWriteSingleBuffer(    (UInt32) readWritePB,
  256.                                             startingDriveBlock,
  257.                                             numDriveBlocks,
  258.                                             readWritePB->userBuffer,
  259.                                             readWritePB->reqCount,
  260.                                             readWritePB->doWrite,
  261.                                             &ReadWriteCompletion );
  262.             return err;
  263.         }
  264.         else if ( readWritePB->doWrite == true )
  265.         {
  266.             // Request is a write, handle all reading and blockcopy commands needed
  267.             // to complete the write request.
  268.             /*
  269.                 Write Flow:
  270.                 Read Lead
  271.                 Read Trail
  272.                 BlockCopy A
  273.                 BlockCopy B
  274.                 1 Write S-G
  275.                     Write Lead
  276.                     Write X
  277.                     Write Trail
  278.             */
  279.             if ( ( readWritePB->startBlock % sysBlksPrDriveBlk) == 0 )
  280.             {
  281.                 //The starting block is on a drive block boundary
  282.                 if (readWritePB->blockCount < sysBlksPrDriveBlk)
  283.                 {
  284.                     // The total data to be transferred is smaller than a drive block
  285.                     // Read the one drive block that has all the system blocks in it
  286.                     startingDriveBlock = (readWritePB->startBlock)/sysBlksPrDriveBlk;
  287.                 }
  288.                 else
  289.                 {
  290.                     // The total data to be transferred crosses a drive block boundary
  291.                     // Read the last drive block that this request touches.
  292.                     startingDriveBlock = (readWritePB->startBlock + readWritePB->blockCount)/sysBlksPrDriveBlk;
  293.                 }
  294.  
  295.                 // We need to read just the trailing block at this point
  296.                 err = ReadWriteSingleBuffer(    (UInt32) readWritePB,
  297.                                                 startingDriveBlock,
  298.                                                 1,                                // We only want to read one block
  299.                                                 (Ptr) TrailingBlockBuffer,        // Read into the trailing buffer
  300.                                                 readWritePB->blockSize,            // We need to read one block
  301.                                                 false,                            // We want to read this block
  302.                                                 &WriteReadTrailingOnlyCompletion );
  303.                 return err;
  304.             }
  305.             else
  306.             {
  307.                 // The starting block is not on a drive block boundary
  308.                 // The leading block needs to be read before anything can be written
  309.                 // We need to read just the leading block at this point
  310.                 startingDriveBlock = (readWritePB->startBlock)/sysBlksPrDriveBlk;
  311.                 err = ReadWriteSingleBuffer(    (UInt32) readWritePB,
  312.                                                 startingDriveBlock,
  313.                                                 1,                                // We only want to read one block
  314.                                                 (Ptr) LeadingBlockBuffer,        // Read into the Leading buffer
  315.                                                 readWritePB->blockSize,            // We need to read one block
  316.                                                 false,                            // We want to read this block
  317.                                                 &WriteReadLeadingCompletion );
  318.             }
  319.         }
  320.         else
  321.         {
  322.             /*
  323.                 Read flow:
  324.                 1 Read S-G:
  325.                     Read Lead
  326.                     Read X
  327.                     Read Trail
  328.                 Blockcopy A
  329.                 BlockCopy B
  330.             */
  331.             if ( ( readWritePB->startBlock % sysBlksPrDriveBlk) == 0 )
  332.             {
  333.                 //The starting block is on a drive block boundary
  334.                 startingDriveBlock = (readWritePB->startBlock)/sysBlksPrDriveBlk;
  335.                 
  336.                 if (readWritePB->blockCount <= sysBlksPrDriveBlk)
  337.                 {
  338.                     // The total data to be transferred is smaller than a drive block
  339.                     readWritePB->sgElements[0].SGAddr = (Ptr) TrailingBlockBuffer;
  340.                     readWritePB->sgElements[0].SGCount = readWritePB->blockSize;
  341.  
  342.                     readWritePB->theSGList.sgNumberElements = 1;
  343.                     readWritePB->leadDataStart = 0;
  344.                     readWritePB->leadDataEnd = 0;
  345.                     readWritePB->trailDataCount = ( readWritePB->blockCount * kFileSystemRequestBlockSize );
  346.                     
  347.                     // The number of blocks to read is just one
  348.                     numDriveBlocks = 1;
  349.                 }
  350.                 else
  351.                 {
  352.                     // The total data to be transferred crosses a drive block boundary
  353.                     readWritePB->sgElements[0].SGAddr = readWritePB->userBuffer;
  354.                     readWritePB->sgElements[0].SGCount = ((readWritePB->blockCount / sysBlksPrDriveBlk) * readWritePB->blockSize);
  355.  
  356.                     readWritePB->sgElements[1].SGAddr = (Ptr) TrailingBlockBuffer;
  357.                     readWritePB->sgElements[1].SGCount = readWritePB->blockSize;
  358.  
  359.                     readWritePB->theSGList.sgNumberElements = 2;
  360.                     readWritePB->leadDataStart = 0;
  361.                     readWritePB->leadDataEnd = 0;
  362.                     readWritePB->trailDataCount = ((readWritePB->blockCount % sysBlksPrDriveBlk) * kFileSystemRequestBlockSize);
  363.                     
  364.                     // The number of blocks to read will be the total number of drive blocks, plus the trailing block
  365.                     numDriveBlocks = (readWritePB->blockCount/sysBlksPrDriveBlk) + 1;
  366.                 }
  367.             }
  368.             else
  369.             {
  370.                 // The starting block is not on a drive block boundary
  371.                 UInt32 blocksInLeading;
  372.                 
  373.                 blocksInLeading = sysBlksPrDriveBlk - (readWritePB->startBlock % sysBlksPrDriveBlk);
  374.                 startingDriveBlock = (readWritePB->startBlock)/sysBlksPrDriveBlk;
  375.                 if ( blocksInLeading > readWritePB->blockCount )
  376.                 {
  377.                     blocksInLeading = readWritePB->blockCount;
  378.                 }
  379.                 
  380.                 readWritePB->sgElements[0].SGAddr = (Ptr) LeadingBlockBuffer;
  381.                 readWritePB->sgElements[0].SGCount = readWritePB->blockSize;
  382.                 readWritePB->leadDataStart = ((readWritePB->startBlock % sysBlksPrDriveBlk) * kFileSystemRequestBlockSize);
  383.                 readWritePB->leadDataEnd = readWritePB->leadDataStart + ( blocksInLeading * kFileSystemRequestBlockSize );
  384.                 if ( readWritePB->blockCount <= blocksInLeading )
  385.                 {
  386.                     // All the data to be transferred is in the LeadingBlockBuffer
  387.                     readWritePB->trailDataCount = 0;
  388.                     readWritePB->theSGList.sgNumberElements = 1;
  389.                     numDriveBlocks = 1;
  390.                 }     
  391.                 else
  392.                 {
  393.                     UInt32 numSystemBlksRemaining = readWritePB->blockCount - blocksInLeading;
  394.                     
  395.                     if ( numSystemBlksRemaining < sysBlksPrDriveBlk )
  396.                     {
  397.                         // We don not have another complete block, read trailing block
  398.                         readWritePB->sgElements[1].SGAddr = (Ptr) TrailingBlockBuffer;
  399.                         readWritePB->sgElements[1].SGCount = readWritePB->blockSize;
  400.                     
  401.                         readWritePB->trailDataCount = ((numSystemBlksRemaining % sysBlksPrDriveBlk) * kFileSystemRequestBlockSize);
  402.                         readWritePB->theSGList.sgNumberElements = 2;
  403.                     
  404.                         // Number of blocks will be the leading + the trailing block
  405.                         numDriveBlocks = 1 + 1;
  406.                     }
  407.                     else
  408.                     {
  409.                         readWritePB->sgElements[1].SGAddr = readWritePB->userBuffer + (blocksInLeading  * kFileSystemRequestBlockSize);
  410.                         readWritePB->sgElements[1].SGCount = ((numSystemBlksRemaining / sysBlksPrDriveBlk) * readWritePB->blockSize);
  411.                         
  412.                         if( (numSystemBlksRemaining % sysBlksPrDriveBlk) == 0 )
  413.                         {
  414.                             // The rest of the data will be in one segment
  415.                             readWritePB->theSGList.sgNumberElements = 2;
  416.                         
  417.                             // Number of blocks will be the leading plus the number of whole drive blocks
  418.                             numDriveBlocks = 1 + (numSystemBlksRemaining / sysBlksPrDriveBlk );
  419.                         }
  420.                         else
  421.                         {
  422.                             // We also need to read a trailing block
  423.                             readWritePB->sgElements[2].SGAddr = (Ptr) TrailingBlockBuffer;
  424.                             readWritePB->sgElements[2].SGCount = readWritePB->blockSize;
  425.                         
  426.                             readWritePB->trailDataCount = ((numSystemBlksRemaining % sysBlksPrDriveBlk) * kFileSystemRequestBlockSize);
  427.                             readWritePB->theSGList.sgNumberElements = 3;
  428.                         
  429.                             // Number of blocks will be the leading plus the number of whole drive blocks + the trailing block
  430.                             numDriveBlocks = 1 + ( numSystemBlksRemaining / sysBlksPrDriveBlk ) +1;
  431.                         }
  432.                     }
  433.                 }
  434.             }
  435.             
  436.             readWritePB->theSGList.sgElementList = readWritePB->sgElements;
  437.             err = ReadWriteScatterGatherList(    
  438.                                             (UInt32) readWritePB,
  439.                                             startingDriveBlock,
  440.                                             numDriveBlocks,
  441.                                             &readWritePB->theSGList,
  442.                                             numDriveBlocks * ( readWritePB->blockSize),
  443.                                             readWritePB->doWrite,
  444.                                             &ReadScatterGatherCompletion );
  445.         }
  446.     }
  447.  
  448.     return err;
  449. }
  450.  
  451. #pragma mark --
  452. #pragma mark SG Completion Routines
  453. void ReadScatterGatherCompletion( UInt32 userData, OSStatus    status )
  454. {
  455.     if ( status == noErr )
  456.     {
  457.         IntReadWritePBPtr    ourPB = (IntReadWritePBPtr) userData;
  458.         
  459.         if (( ourPB->leadDataStart != 0 ) || ( ourPB->leadDataEnd != 0 ))
  460.         {
  461.             // Copy the data from the leading buffer to the user's buffer
  462.             BlockCopy( LeadingBlockBuffer + ourPB->leadDataStart, ourPB->userBuffer, ourPB->leadDataEnd - ourPB->leadDataStart );
  463.         }
  464.         
  465.         if ( ourPB->trailDataCount != 0 )
  466.         {
  467.             // Copy the data from the trailing buffer to the user's buffer
  468.             UInt32 bufferOffset;
  469.             
  470.             bufferOffset = ourPB->reqCount - ourPB->trailDataCount;
  471.             BlockCopy( TrailingBlockBuffer, ourPB->userBuffer + bufferOffset, ourPB->trailDataCount );
  472.         }
  473.     }
  474.     
  475.     ReadWriteCompletion( userData,  status );
  476. }
  477.  
  478. void WriteReadTrailingOnlyCompletion( UInt32 userData, OSStatus    status )
  479. {
  480.     OSStatus            err = status;
  481.  
  482.     // This is the completion routine after reading the trailing block for 
  483.     // requests that start on a drive boundary.
  484.     if ( err == noErr )
  485.     {
  486.         UInt32                startingDriveBlock, numDriveBlocks;
  487.         UInt32                standardBlockSize = kFileSystemRequestBlockSize;
  488.         IntReadWritePBPtr    ourPB = (IntReadWritePBPtr) userData;
  489.         UInt8                sysBlksPrDriveBlk;
  490.         
  491.         sysBlksPrDriveBlk = (ourPB->blockSize)/standardBlockSize;
  492.         startingDriveBlock = (ourPB->startBlock)/sysBlksPrDriveBlk;
  493.         
  494.         // Handle all copies from our buffers to the request buffers
  495.         if ( ourPB->blockCount < sysBlksPrDriveBlk )
  496.         {
  497.             // All the data is in one drive block
  498.             // Copy the data from the user buffer into the start of the trailing buffer
  499.             BlockCopy( ourPB->userBuffer, TrailingBlockBuffer, ourPB->reqCount );
  500.             
  501.             // Now write the block out as a single buffer
  502.             err = ReadWriteSingleBuffer(    (UInt32) ourPB,
  503.                                             startingDriveBlock,
  504.                                             1,                            // Write just one drive block
  505.                                             (Ptr) TrailingBlockBuffer,    // The Trailing Buffer has the data to write 
  506.                                             ourPB->blockSize,            // We are writing one complete drive block
  507.                                             ourPB->doWrite,
  508.                                             &ReadWriteCompletion );
  509.         }
  510.         else
  511.         {
  512.             // The data is in multiple drive blocks
  513.             UInt32    bufferOffset;
  514.             
  515.             //bufferOffset = ((ourPB->blockCount) - (ourPB->blockCount % sysBlksPrDriveBlk)) * standardBlockSize;
  516.             bufferOffset = (ourPB->blockCount/sysBlksPrDriveBlk) * ourPB->blockSize;
  517.  
  518.             // Copy the data from the user buffer into the start of the trailing buffer
  519.             BlockCopy( ourPB->userBuffer + bufferOffset, TrailingBlockBuffer, ourPB->reqCount - bufferOffset );
  520.             // Write all complete drive blocks plus the trailing buffer
  521.             ourPB->sgElements[0].SGAddr     = ourPB->userBuffer;
  522.             ourPB->sgElements[0].SGCount     = ((ourPB->blockCount / sysBlksPrDriveBlk) * ourPB->blockSize);
  523.  
  524.             ourPB->sgElements[1].SGAddr     = (Ptr) TrailingBlockBuffer;
  525.             ourPB->sgElements[1].SGCount     = ourPB->blockSize;
  526.  
  527.             ourPB->theSGList.sgNumberElements = 2;
  528.             
  529.             // The number of blocks to write will be the total number of drive blocks, plus the trailing block
  530.             // Use the standard completion routine because the request will be finished when this write completes.
  531.             numDriveBlocks = (ourPB->blockCount/sysBlksPrDriveBlk) + 1;
  532.             ourPB->theSGList.sgElementList = ourPB->sgElements;
  533.             err = ReadWriteScatterGatherList(    
  534.                                             (UInt32) ourPB,
  535.                                             startingDriveBlock,
  536.                                             numDriveBlocks,
  537.                                             &ourPB->theSGList,
  538.                                             numDriveBlocks * ( ourPB->blockSize),
  539.                                             ourPB->doWrite,
  540.                                             &ReadWriteCompletion );
  541.         }
  542.     }
  543.  
  544.     if ( err != kRequestPending )
  545.     {
  546.         // An error occurred, let the standard completion routine
  547.         // determine if it should be retried, or if an error should
  548.         // be returned back to the system.
  549.         ReadWriteCompletion( userData,  err );
  550.     }
  551. }
  552.  
  553. void WriteReadLeadingCompletion( UInt32 userData, OSStatus    status )
  554. {
  555.     OSStatus    err = status;
  556.     
  557.     // This is the completion routine after reading the leading block for 
  558.     // requests that do not start on a drive boundary.
  559.     if ( err == noErr )
  560.     {
  561.         UInt32                startingDriveBlock, numDriveBlocks;
  562.         UInt32                standardBlockSize = kFileSystemRequestBlockSize;
  563.         IntReadWritePBPtr    ourPB = (IntReadWritePBPtr) userData;
  564.         UInt8                sysBlksPrDriveBlk;
  565.         UInt32                 blocksInLeading;
  566.         UInt32                 leadingBufferOffset;
  567.         
  568.         sysBlksPrDriveBlk = (ourPB->blockSize)/standardBlockSize;
  569.         startingDriveBlock = (ourPB->startBlock)/sysBlksPrDriveBlk;
  570.                 
  571.         blocksInLeading = sysBlksPrDriveBlk - (ourPB->startBlock % sysBlksPrDriveBlk);
  572.         if ( blocksInLeading > ourPB->blockCount )
  573.         {
  574.             blocksInLeading = ourPB->blockCount;
  575.         }
  576.         
  577.         // Copy the data from the user buffer into the leading buffer at the calculated offset.
  578.         leadingBufferOffset = ((ourPB->startBlock % sysBlksPrDriveBlk) * standardBlockSize);
  579.         BlockCopy( ourPB->userBuffer, (LeadingBlockBuffer + leadingBufferOffset), ( blocksInLeading * standardBlockSize ));
  580.         
  581.         // Handle all copies from our buffers to the request buffers
  582.         if ( ourPB->blockCount <= blocksInLeading )
  583.         {
  584.             // All the data to be transferred will be in the LeadingBlockBuffer
  585.             // Now write the block out as a single buffer
  586.             err = ReadWriteSingleBuffer(    (UInt32) ourPB,
  587.                                             startingDriveBlock,
  588.                                             1,                            // Write just one drive block
  589.                                             (Ptr) LeadingBlockBuffer,    // The Leading Buffer has all the data to write 
  590.                                             ourPB->blockSize,            // We are writing one complete drive block
  591.                                             ourPB->doWrite,
  592.                                             &ReadWriteCompletion );        // This completes the request, use the standard completion
  593.         }
  594.         else
  595.         {
  596.             UInt32 numSystemBlksRemaining = ourPB->blockCount - blocksInLeading;
  597.  
  598.             if( (numSystemBlksRemaining % sysBlksPrDriveBlk) == 0 )
  599.             {
  600.                 // The rest of the data will be in one segment
  601.                 // Build Scatter-Gather list with the Leading block
  602.                 // and the remainder of the user buffer.
  603.                 ourPB->sgElements[0].SGAddr = (Ptr) LeadingBlockBuffer;
  604.                 ourPB->sgElements[0].SGCount = ourPB->blockSize;
  605.  
  606.                 ourPB->sgElements[1].SGAddr = ourPB->userBuffer + (blocksInLeading * standardBlockSize);
  607.                 ourPB->sgElements[1].SGCount = (numSystemBlksRemaining/sysBlksPrDriveBlk) * ourPB->blockSize;
  608.  
  609.                 ourPB->theSGList.sgNumberElements = 2;
  610.                 
  611.                 // The number of blocks to write will be the leading block + total number of remaining drive blocks
  612.                 numDriveBlocks = 1 + (numSystemBlksRemaining/sysBlksPrDriveBlk);
  613.                 ourPB->theSGList.sgElementList = ourPB->sgElements;
  614.                 err = ReadWriteScatterGatherList(    
  615.                                                 (UInt32) ourPB,    
  616.                                                 startingDriveBlock,        
  617.                                                 numDriveBlocks,            // Write the total number of system blocks
  618.                                                 &ourPB->theSGList,        // Use the SG List to for buffer and bytes to write
  619.                                                 numDriveBlocks * ( ourPB->blockSize),
  620.                                                 ourPB->doWrite,
  621.                                                 &ReadWriteCompletion );    // This completes the request, use the standard completion
  622.             }
  623.             else
  624.             {
  625.                 // We also need to read a trailing block before anything can be written
  626.                 // We need to read just the trailing block at this point
  627.                 
  628.                 // Modify the starting block to be the starting block for the trailing buffer
  629.                 startingDriveBlock += (( numSystemBlksRemaining / sysBlksPrDriveBlk ) +1 );
  630.                 err = ReadWriteSingleBuffer(    (UInt32) ourPB,
  631.                                                 startingDriveBlock,
  632.                                                 1,                            // We only want to read one block
  633.                                                 (Ptr) TrailingBlockBuffer,    // Read into the Trailing buffer
  634.                                                 ourPB->blockSize,            // We need to read one block
  635.                                                 false,                        // We want to read this block
  636.                                                 &WriteReadTrailingCompletion );
  637.             }
  638.         }
  639.     }
  640.  
  641.     if ( err != kRequestPending )
  642.     {
  643.         // An error occurred, let the standard completion routine
  644.         // determine if it should be retried, or if an error should
  645.         // be returned back to the system.
  646.         ReadWriteCompletion( userData,  err );
  647.     }
  648. }
  649.  
  650. void WriteReadTrailingCompletion( UInt32 userData, OSStatus    status )
  651. {
  652.     OSStatus    err = status;
  653.     
  654.     // This is the completion routine after reading the trailing block for 
  655.     // requests that do not start on a drive block boundary and do not end 
  656.     // on a drive block boundary.
  657.     if ( err == noErr )
  658.     {
  659.         UInt32                startingDriveBlock, numDriveBlocks;
  660.         UInt32                standardBlockSize = kFileSystemRequestBlockSize;
  661.         IntReadWritePBPtr    ourPB = (IntReadWritePBPtr) userData;
  662.         UInt8                sysBlksPrDriveBlk;
  663.         UInt32                 blocksInLeading;
  664.         UInt32                 userBufferOffset;
  665.         UInt32                 numSystemBlksRemaining;
  666.         
  667.         sysBlksPrDriveBlk = (ourPB->blockSize)/standardBlockSize;
  668.         startingDriveBlock = (ourPB->startBlock)/sysBlksPrDriveBlk;
  669.                 
  670.         // Copy the data from the user buffer to the Trailing block
  671.         blocksInLeading = sysBlksPrDriveBlk - (ourPB->startBlock % sysBlksPrDriveBlk);
  672.         if ( blocksInLeading > ourPB->blockCount )
  673.         {
  674.             blocksInLeading = ourPB->blockCount;
  675.         }
  676.         
  677.         numSystemBlksRemaining = ourPB->blockCount - blocksInLeading;
  678.         userBufferOffset = ( ( blocksInLeading * standardBlockSize )  + ((numSystemBlksRemaining/sysBlksPrDriveBlk) * ourPB->blockSize)); 
  679.         BlockCopy( (ourPB->userBuffer + userBufferOffset), TrailingBlockBuffer, (ourPB->reqCount - userBufferOffset));
  680.         
  681.         if ( numSystemBlksRemaining < sysBlksPrDriveBlk )
  682.         {
  683.             // We do not have another complete block,
  684.             // The SG List will be just the leading and trailing buffers
  685.             ourPB->sgElements[0].SGAddr = (Ptr) LeadingBlockBuffer;
  686.             ourPB->sgElements[0].SGCount = ourPB->blockSize;
  687.  
  688.             ourPB->sgElements[1].SGAddr = (Ptr) TrailingBlockBuffer;
  689.             ourPB->sgElements[1].SGCount = ourPB->blockSize;
  690.  
  691.             ourPB->theSGList.sgNumberElements = 2;
  692.             
  693.             // The number of blocks to write will be the leading block + the trailing block
  694.             numDriveBlocks = 1 + 1;
  695.         }
  696.         else
  697.         {
  698.             // The SG List will be the leading buffer, all complete drive blocks
  699.             // from the user buffer, and the trailing buffer
  700.             ourPB->sgElements[0].SGAddr = (Ptr) LeadingBlockBuffer;
  701.             ourPB->sgElements[0].SGCount = ourPB->blockSize;
  702.  
  703.             ourPB->sgElements[1].SGAddr = ourPB->userBuffer + (blocksInLeading * standardBlockSize);
  704.             ourPB->sgElements[1].SGCount = (numSystemBlksRemaining/sysBlksPrDriveBlk) * ourPB->blockSize;
  705.  
  706.             ourPB->sgElements[2].SGAddr = (Ptr) TrailingBlockBuffer;
  707.             ourPB->sgElements[2].SGCount = ourPB->blockSize;
  708.  
  709.             ourPB->theSGList.sgNumberElements = 3;
  710.             
  711.             // The number of blocks to write will be the leading block + total number of remaining drive blocks
  712.             // + the trailing buffer
  713.             numDriveBlocks = 1 + (numSystemBlksRemaining/sysBlksPrDriveBlk) + 1;
  714.         }
  715.  
  716.         ourPB->theSGList.sgElementList = ourPB->sgElements;
  717.         err = ReadWriteScatterGatherList(    
  718.                                         (UInt32) ourPB,    
  719.                                         startingDriveBlock,        
  720.                                         numDriveBlocks,            // Write the total number of system blocks
  721.                                         &ourPB->theSGList,        // Use the SG List for buffer and bytes to write
  722.                                         numDriveBlocks * ( ourPB->blockSize),
  723.                                         ourPB->doWrite,
  724.                                         &ReadWriteCompletion );    // This completes the request, use the standard completion
  725.     }
  726.     
  727.     if ( err != kRequestPending )
  728.     {
  729.         // An error occurred, let the standard completion routine
  730.         // determine if it should be retried, or if an error should
  731.         // be returned back to the system.
  732.         ReadWriteCompletion( userData,  err );
  733.     }
  734. }
  735.  
  736. #pragma mark --
  737. #pragma mark Standard Completion Routines
  738. void ReadWriteCompletion(    UInt32        userData,
  739.                             OSStatus    status )
  740. {
  741.     IntReadWritePBPtr    ourPB = (IntReadWritePBPtr) userData;
  742.     Boolean             wasWrite;
  743.     OSStatus            returnStatus;
  744.     
  745.     returnStatus = status;
  746.     wasWrite = ourPB->doWrite;
  747.  
  748.     if( returnStatus == noErr )
  749.     {
  750.         // This was a read command, and no errors occurred, finish the IO request and
  751.         // return to the system.
  752.         returnStatus = noErr;
  753.     }
  754.     else
  755.     {
  756.         // An error occurred on the initial command, check to see if it should be retried.
  757.         //if ((ourPB->retryCount < kReadWriteRetryCount) && ( returnStatus == kDeviceAccessDataTransferErrorOccurred ))
  758.         if (ourPB->retryCount < kReadWriteRetryCount)
  759.         {
  760.             // We have not yet exceeded the retry count, so try the operation again
  761.             // Increment our retry counter
  762.             ourPB->retryCount += 1;
  763.     
  764.             // Send the command out again
  765.             returnStatus = ConvertSystemBlocksToDriveBlocks( ourPB );
  766.         }
  767.         else
  768.         {
  769.             // Since we only get here if an error occurrs on the command, 
  770.             // and so the request couldn't be completed, report back an ioErr to the system.
  771.             returnStatus = ioErr;
  772.         }
  773.     }
  774.     
  775.     if( returnStatus != kRequestPending)
  776.     {
  777.         // The request is either finished, or got an error on the retry;
  778.         // therefore, signal completion of the command to the client
  779.         (*ourPB->userCompletion) ( ourPB->userData, returnStatus );
  780.     }
  781. }
  782.